Skip to main content

谈谈 Context

是什么

  1. Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
  2. 需要注意场景是否应该使用 Context,因为这样会使用组件复用性变差,或许 render props 可以解决问题。

怎么用

预览地址

  1. React.createContext 创建一个上下文的容器, defaultValue 可以设置共享的默认数据。
const {Provider, Consumer} = React.createContext(defaultValue);
  1. Provider 数据生产者

用于生产共享数据的地方,value 即为放置共享的数据。

<Provider value={/*共享的数据*/}>
/*里面可以渲染对应的内容*/
</Provider>
  1. Consumer 数据消费者

消费供应商 Provider 产生数据。Consumer 需要嵌套在生产者下面,通过回调的方式拿到共享的数据源,当然也可以单独使用,那就只能消费到上文提到的 defaultValue。

<Consumer>
{value => /*根据上下文 进行渲染相应内容*/}
</Consumer>

示例

import React, { createContext } from "react";

// 英文状态
const enStrings = {
submit: "Submit",
cancel: "Cancel"
};
// 中文状态
const cnStrings = {
submit: "提交",
cancel: "取消"
};

// 创建一个数据提供与数据消费者,同时可以赋初值
const {
Provider, // 数据提供
Consumer // 数据消费者
} = createContext(enStrings);

// 父组件数据提供者
class App extends React.Component {
state = { locale: cnStrings };

// 切换语言
toggleLocale = () => {
const locale = this.state.locale === enStrings ? cnStrings : enStrings;
this.setState({ locale });
};

render() {
return (
<Provider value={this.state.locale}>
<button onClick={this.toggleLocale}>切换语言</button>
<Child />
</Provider>
);
}
}

// 子组件消费数据:Consumer接受数据
class Child extends React.Component {
render() {
return (
<Consumer>
{(locale) => {
console.log("locale", locale);
return (
<div>
<button>{locale.cancel}</button>
<button>{locale.submit}</button>
</div>
);
}}
</Consumer>
);
}
}

export default App;

Context 缺点

  1. context 相当于全局变量,难以追溯数据源
  2. 耦合度高,即不利于组件复用也不利于测试
  3. 在老版 Context(v16.3 之前):当 props 改变或者 setState 被调用,生成新的 context,但是 shouldComponentUpdate 返回的 false 会 block 住 context,导致没有更新。因此新版 Context 改成了传播不受限制于 shouldComponentUpdate,在顶层组件跳过更新时也能更新。

参考文章